package excmy

import (
	"database/sql"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"strings"
)

type ExcmyDB struct {
	DB *sql.DB
}

var DataBaseLocation string = "./excmy.db"

var DB4g *sql.DB

func NewExcmyDB() *ExcmyDB {
	e := new(ExcmyDB)
	ddb, err := sql.Open("sqlite3", DataBaseLocation)
	DB4g = ddb
	if err != nil {
		log.Panic(err)
	}
	fmt.Println("Database connected", DataBaseLocation)
	e.DB = ddb
	return e
}

func (e *ExcmyDB) AddSheetFromStringSlice(tableName string, stringSlice [][]string) error {
	//fmt.Println(len(gbk[0]), numberToColumn(len(gbk[0])))
	tableSQL, err := generateCreateTableSQL(tableName, "A", numberToColumn(len(stringSlice[0])))
	fmt.Println(tableSQL)
	if err != nil {
		panic(err)
	}

	_, err = e.DB.Exec(tableSQL)
	if err != nil {
		panic(err)
	}
	//开启事务
	tx, err := e.DB.Begin()
	if err != nil {
		panic(err)
	}

	stmt, err := tx.Prepare(generateInsertSQL(tableName, "A", numberToColumn(len(stringSlice[0]))))
	if err != nil {
		panic(err)
	}

	//事务数据
	for _, v := range stringSlice {
		// 创建一个 []any 类型的切片，并将 record 中的元素添加到这个新切片中
		var anyRecord []any
		for _, str := range v {
			anyRecord = append(anyRecord, str) // 这里 str 已经是 interface{} 类型，因为可以隐式转换为 any
		}
		_, err := stmt.Exec(anyRecord...)
		if err != nil {
			panic(err)
		}
	}

	//事务提交
	err = tx.Commit()
	if err != nil {
		log.Fatal(err)
	}

	return nil
}

// AddSheet 将sheet添加进数据库,beginLine是数据起始行第一行，from，to是从哪一列到哪一列
func (e *ExcmyDB) AddSheet(sheet *Sheet, beginLine int, from, to string) error {
	cell, err := sheet.NewCell(from + int2string(beginLine))
	if err != nil {
		panic(err)
	}

	read := cell.Read(to)

	tableSQL, err := generateCreateTableSQL(sheet.Name, from, to)
	fmt.Println(tableSQL)
	if err != nil {
		panic(err)
	}
	_, err = e.DB.Exec(tableSQL)
	if err != nil {
		panic(err)
	}
	//开启事务
	tx, err := e.DB.Begin()
	if err != nil {
		panic(err)
	}

	stmt, err := tx.Prepare(generateInsertSQL(sheet.Name, from, to))
	if err != nil {
		panic(err)
	}

	//事务数据
	for _, v := range read {
		// 创建一个 []any 类型的切片，并将 record 中的元素添加到这个新切片中
		var anyRecord []any
		for _, str := range v {
			anyRecord = append(anyRecord, str) // 这里 str 已经是 interface{} 类型，因为可以隐式转换为 any
		}
		_, err := stmt.Exec(anyRecord...)
		if err != nil {
			panic(err)
		}
	}

	//事务提交
	err = tx.Commit()
	if err != nil {
		log.Fatal(err)
	}

	return nil
}

// AddSheetFromCSV 读取CSV文件到数据库。file是文件路径，tableName是表名字,默认全加进去
func (e *ExcmyDB) AddSheetFromCSV(file string, tableName string) error {
	gbk, err := CSVReadGBK(file)
	if err != nil {
		panic(err)
	}

	fmt.Println(len(gbk[0]), numberToColumn(len(gbk[0])))

	tableSQL, err := generateCreateTableSQL(tableName, "A", numberToColumn(len(gbk[0])))
	fmt.Println(tableSQL)
	if err != nil {
		panic(err)
	}

	_, err = e.DB.Exec(tableSQL)
	if err != nil {
		panic(err)
	}
	//开启事务
	tx, err := e.DB.Begin()
	if err != nil {
		panic(err)
	}

	stmt, err := tx.Prepare(generateInsertSQL(tableName, "A", numberToColumn(len(gbk[0]))))
	if err != nil {
		panic(err)
	}

	//事务数据
	for _, v := range gbk {
		// 创建一个 []any 类型的切片，并将 record 中的元素添加到这个新切片中
		var anyRecord []any
		for _, str := range v {
			anyRecord = append(anyRecord, str) // 这里 str 已经是 interface{} 类型，因为可以隐式转换为 any
		}
		_, err := stmt.Exec(anyRecord...)
		if err != nil {
			panic(err)
		}
	}

	//事务提交
	err = tx.Commit()
	if err != nil {
		log.Fatal(err)
	}

	return nil

}

// generateInsertSQL 生成一个 INSERT SQL 语句，其中包含指定数量的占位符
func generateInsertSQL(tableName string, from, to string) string {
	// 生成占位符列表

	placeholders := make([]string, columnToNumber(to)-columnToNumber(from)+1)
	for i := range placeholders {
		placeholders[i] = "?"
	}

	// 构建 INSERT 语句
	//columns := strings.Repeat("column_name", placeholderCount) // 这里应该使用实际的列名，但为了演示，我们使用重复的占位符文本
	// 注意：在实际应用中，你应该替换为实际的列名列表，可能是通过查询数据库元数据来获取的
	// 由于我们不知道实际的列名，这里仅作为示例
	//sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s);", tableName, strings.Replace(columns, "column_name", "column1, column2, column3, ...", -1)[:len(placeholders)*len("column_name")-len("column_name")+len("column1, column2, column3, ...")-len(", ")], strings.Join(placeholders, ", "))

	// 但是上面的列名部分是不正确的，因为我们不能硬编码列名。我们应该省略列名部分（让数据库根据表结构推断），或者提供一个正确的列名列表。
	// 正确的做法应该是这样的：
	correctSQL := fmt.Sprintf("INSERT INTO %s VALUES (%s);", tableName, strings.Join(placeholders, ", "))

	// 打印生成的 SQL 语句
	fmt.Println("Generated SQL:", correctSQL)

	// 返回生成的 SQL 语句
	return correctSQL
}

// 生成sql CREATE 语句
func generateCreateTableSQL(tableName string, startCol, endCol string) (string, error) {
	startNum := columnToNumber(startCol)
	//if err != nil {
	//	return "", fmt.Errorf("invalid start column identifier: %w", err)
	//}
	endNum := columnToNumber(endCol)
	//if err != nil {
	//	return "", fmt.Errorf("invalid end column identifier: %w", err)
	//}

	// 生成列定义
	var columns []string
	for i := startNum; i <= endNum; i++ {
		colIdent := numberToColumn(i)
		fmt.Println(i, colIdent)
		columns = append(columns, fmt.Sprintf("'%s' TEXT", colIdent))
	}

	// 构造 CREATE TABLE SQL
	//tableName := "DynamicTable"
	sql := fmt.Sprintf("CREATE TABLE %s (%s);", tableName, strings.Join(columns, ", "))

	return sql, nil
}
